(import
 (except (rnrs base) let-values map error)
 (only (guile)
       lambda* λ
       current-output-port)
 (fileio)
 (srfi srfi-1)
 ;; let-values
 (srfi srfi-11)
 ;; hash tables
 (srfi srfi-69)
 (ice-9 pretty-print))


(define lines (get-lines-from-file "input"))

(define num-rows (length lines))
(define num-cols (string-length (first lines)))

(define trees
  (let ([trees (make-array 0 num-rows num-cols)])
    (let iter-rows ([lines° lines] [row-ind 0])
      (cond
       [(null? lines°) trees]
       [else
        (let iter-cols ([numbers-line° (first lines°)]
                        [col-ind 0])
          (unless (string-null? numbers-line°)
            (array-set! trees
                        (string->number (substring numbers-line° 0 1))
                        row-ind
                        col-ind)
            (iter-cols (substring numbers-line° 1)
                       (+ col-ind 1))))
        (iter-rows (drop lines° 1)
                   (+ row-ind 1))]))))

(define step-down
  (λ (row col)
    (values (+ row 1) col)))

(define step-left
  (λ (row col)
    (values row (- col 1))))

(define step-up
  (λ (row col)
    (values (- row 1) col)))

(define step-right
  (λ (row col)
    (values row (+ col 1))))

(define array-len-in-dim
  (λ (arr dim)
    (let* ([shape (array-shape arr)]
           [dim-min-max (list-ref shape dim)])
      (+ (- (second dim-min-max)
            (first dim-min-max))
         1))))

(define visible-in-direction?
  (λ (trees init-row-ind init-col-ind step)
    (let ([tree-height (array-ref trees init-row-ind init-col-ind)])
      ;; already step away 1 step towards the border
      (let-values ([(next-row-ind next-col-ind) (step init-row-ind init-col-ind)])
        (let iter ([row-ind° next-row-ind] [col-ind° next-col-ind])
          (cond
           [(array-in-bounds? trees row-ind° col-ind°)
            (if (>= (array-ref trees row-ind° col-ind°) tree-height)
                #f
                (let-values ([(next-row-ind next-col-ind) (step row-ind° col-ind°)])
                  (iter next-row-ind next-col-ind)))]
           [else #t]))))))

(define visible?
  (λ (trees row-ind col-ind)
    ;; idea: calculate number of directions in which tree is visible
    (or (visible-in-direction? trees row-ind col-ind step-up)
        (visible-in-direction? trees row-ind col-ind step-right)
        (visible-in-direction? trees row-ind col-ind step-down)
        (visible-in-direction? trees row-ind col-ind step-left))))

(define calc-tree-visibility
  (λ (trees)
    (let* ([rows (array-len-in-dim trees 0)]
           [cols (array-len-in-dim trees 1)]
           [visibility (make-array 0 rows cols)]
           [max-row-ind (- rows 1)]
           [max-col-ind (- cols 1)])
      (let iter-rows ([row-ind° 0])
        (cond
         [(<= row-ind° max-row-ind)
          (let iter-cols ([col-ind° 0])
            (cond
             ;; go to next row
             [(<= col-ind° max-col-ind)
              (cond
               [(visible? trees row-ind° col-ind°)
                (simple-format (current-output-port) "r:~a,c:~a is visibile\n" row-ind° col-ind°)
                (array-set! visibility 1 row-ind° col-ind°)
                (iter-cols (+ col-ind° 1))]
               [else
                (iter-cols (+ col-ind° 1))])]
             [else
              (iter-rows (+ row-ind° 1))]))]
         [else visibility])))))

(simple-format (current-output-port)
               "~a\n"
               (apply
                +
                (map (λ (row) (apply + row))
                     (array->list (calc-tree-visibility trees)))))

;; (define count-in-direction
;;   (λ (trees start-row-ind start-col-ind next already-seen-table)
;;     (let ([rows (array-len-in-dim trees 0)]
;;           [cols (array-len-in-dim trees 1)])
;;       (let iter ([row-ind start-row-ind]
;;                  [col-ind start-col-ind]
;;                  [max-tree-height° -1]
;;                  [counter 0])
;;         (cond
;;          [(>= col-ind cols) counter]
;;          [(< col-ind 0) counter]
;;          [(>= row-ind rows) counter]
;;          [(< row-ind 0) counter]
;;          [else
;;           (let ([current-tree-height (array-ref trees row-ind col-ind)])
;;             (cond
;;              [(> current-tree-height max-tree-height°)
;;               (let-values ([(next-row-ind next-col-ind) (next row-ind col-ind)])
;;                 (hash-table-ref table key [default-thunk])

;;                 ;; (cond
;;                 ;;  [(hash-table-ref/default already-seen-table (cons row-ind col-ind) #f)
;;                 ;;   (iter next-row-ind
;;                 ;;         next-col-ind
;;                 ;;         current-tree-height
;;                 ;;         (+ counter 1))
;;                 ;;   ]
;;                 ;;  [else ...])
;;                 )]
;;              [else
;;               (let-values ([(next-row-ind next-col-ind) (next row-ind col-ind)])
;;                 (iter next-row-ind
;;                       next-col-ind
;;                       max-tree-height°
;;                       counter))]))])))))


;; (define count-from-side
;;   (λ (trees
;;       start-row-ind start-col-ind
;;       max-row-ind max-col-ind
;;       next-line
;;       next-tree
;;       already-seen-table)
;;     (let ([rows (array-len-in-dim trees 0)]
;;           [cols (array-len-in-dim trees 0)])
;;       (let iter ([row-ind start-row-ind]
;;                  [col-ind start-col-ind]
;;                  [counter 0])
;;         (cond
;;          ;; in bounds check
;;          [(and (<= row-ind max-row-ind)
;;                (>= row-ind 0)
;;                (<= col-ind max-col-ind)
;;                (>= col-ind 0))
;;           (simple-format (current-output-port) "starting at: r=~a,c=~a\n" row-ind col-ind)
;;           ;; Calculate the starting point of the next line to count
;;           ;; visible trees in.
;;           (let-values ([(next-row-ind next-col-ind) (next-line row-ind col-ind)])
;;             (iter next-row-ind
;;                   next-col-ind
;;                   (+ counter
;;                      (count-in-direction trees
;;                                          row-ind
;;                                          col-ind
;;                                          next-tree
;;                                          already-seen-table))))]
;;          [else counter])))))

;; (define count-trees
;;   (λ (trees)
;;     (let ([rows (array-len-in-dim trees 0)]
;;           [cols (array-len-in-dim trees 0)]
;;           [already-seen-table (make-hash-table equal?)])
;;       (simple-format (current-output-port) "rows: ~a\n" rows)
;;       (simple-format (current-output-port) "cols: ~a\n" cols)
;;       (+ 4  ; 4 corners
;;          ;; from left
;;          (count-from-side trees
;;                           1 0 (- rows 2) (- cols 1)
;;                           step-down
;;                           step-right
;;                           already-seen-table)
;;          ;; from right
;;          (count-from-side trees
;;                           1 (- cols 1) (- rows 2) (- cols 1)
;;                           step-down
;;                           step-left
;;                           already-seen-table)
;;          ;; from top
;;          (count-from-side trees
;;                           0 1 (- rows 1) (- cols 2)
;;                           step-right
;;                           step-down
;;                           already-seen-table)
;;          ;; from bottom
;;          (count-from-side trees
;;                           (- rows 1) 1 (- rows 1) (- cols 2)
;;                           step-right
;;                           step-up
;;                           already-seen-table)))))


;; (display (simple-format #f "~a\n" (array-shape trees)))

;; (display (simple-format #f "~a\n" (calc-tree-visibility trees)))
;; (pretty-print (array->list trees))
